#include <sys_config.h>
#include <types.h>
#include <osal/osal.h>
#include <api/libc/printf.h>
#include <api/libc/string.h>
#include <hld/hld_dev.h>
#include <hld/dmx/dmx_dev.h>
#include <hld/dmx/dmx.h>
#include <hld/smc/smc.h>
#include <api/libtsi/si_monitor.h>
#ifdef LIB_TSI3_FULL
#include <api/libtsi/sie.h>
#else
#include <api/libtsi/siae.h>
#endif

#include <api/libcas/mcas.h>
#include <api/libcas/mcas_ca_info.h>
#include "mcas_card.h"

//#define MCAS_DEBUG
#ifdef MCAS_DEBUG
#define MCAS_DEBUG_PRINTF	libc_printf
#define MCAS_DEBUG_DUMP(data,len) { const int l=(len); int i;\
                         for(i=0 ; i<l ; i++) MCAS_DEBUG_PRINTF(" 0x%02x",*((data)+i)); \
                         MCAS_DEBUG_PRINTF("\n"); }
#else
#define MCAS_DEBUG_PRINTF(...)	do{}while(0)
#define MCAS_DEBUG_DUMP(data,len) ;
#endif


#define MAX_CMT_LENGTH			256
#define SECTION_BUFFER_SIZE	1024

#define CA_SYSTEM_MASK		0xFF00
#define CA_INFO_MAX_COUNT 16

static UINT32 mcas_pmt_crc = 0;
static mcas_t mcas_structure;
static UINT8 ecm_buffer[MAX_CMT_LENGTH];
static UINT8 emm_buffer[MAX_CMT_LENGTH];
static UINT8 cat_buffer[SECTION_BUFFER_SIZE];

static cas_filter_t ecm_filter, cat_filter, emm_filter;


static UINT8 used_ecm_count = 0;

typedef struct
{
	UINT16	ca_system_id;
	UINT16    ecm_pid;
} STASK_CA_ECM;
static STASK_CA_ECM 		stCA_ECM[CA_INFO_MAX_COUNT];

static UINT8 used_emm_count = 0;
typedef struct
{
	UINT16	ca_system_id;
	UINT16    emm_pid;
} STASK_CA_EMM;
static STASK_CA_EMM 		stCA_EMM[CA_INFO_MAX_COUNT];

static UINT8 uiCurrentTryingCount;



/*********************************************

**********************************************/

static void mcas_send_msg(mcas_msg_type_t type, UINT32 param)
{
	mcas_msg_t msg;

	msg.type = type;
	msg.param = param;
	osal_msgqueue_send(mcas_structure.msgque_id, &msg, sizeof(mcas_msg_t), OSAL_WAIT_FOREVER_TIME);
}

#ifdef LIB_TSI3_FULL
void mcas_stop_filter(cas_filter_t *filter)
{
	if(filter->pid != 0)
	{
		//siae_abort(siae_id, filter->pid, &filter->filter_restrict);
		//close the filter forcely
		sie_abort(filter->pid, NULL);
		MEMSET(filter, 0, sizeof(cas_filter_t));
	}
}
#else
void mcas_stop_filter(cas_filter_t *filter)
{
	INT32 siae_id;

	siae_id = siae_acquire_id();
	if (siae_id < 0) 
	{
		MCAS_DEBUG_PRINTF("stop_filter(): siae id < 0!\n");
		return;
	}
	if(filter->pid != 0)
	{
		//siae_abort(siae_id, filter->pid, &filter->filter_restrict);
		//close the filter forcely
		siae_abort(siae_id, filter->pid, NULL);
		MEMSET(filter, 0, sizeof(cas_filter_t));
	}
}

#endif

static UINT32 pmt_crc_value = 0;
static void mcas_pmt_section_callback(UINT8 *section, INT32 length, UINT16 param);
static INT32 mcas_cat_section_callback(UINT8 *buffer, INT32  len , UINT16 param);

#ifdef NEW_DEMO_FRAME
INT32 api_mcas_start_service(UINT16 channel_index, UINT32 mon_id)
#else
INT32 api_mcas_start_service(UINT16 channel_index)
#endif
{
	if(mcas_structure.state == MCAS_STATE_UNREGISTER)
	{
		return !SUCCESS;
	}
	//here can clear the ecm info table
	MEMSET(stCA_ECM, 0, sizeof(stCA_ECM));

	MCAS_DEBUG_PRINTF("api_mcas_start_service channel=%d!\n", channel_index);
#ifdef NEW_DEMO_FRAME
	sim_register_scb(mon_id, mcas_pmt_section_callback, NULL);
#endif
	pmt_crc_value = 0;

	return SUCCESS;
}
#ifdef NEW_DEMO_FRAME
INT32 api_mcas_stop_service(UINT32 mon_id)
#else
INT32 api_mcas_stop_service()
#endif
{
	mcas_stop_filter(&ecm_filter);
	mcas_structure.state &= ~MCAS_STATE_ECM;
#ifdef NEW_DEMO_FRAME
	sim_unregister_scb(mon_id, mcas_pmt_section_callback);
#endif
	return SUCCESS;
}

#ifdef GET_CAT_BY_SIM
#ifdef NEW_DEMO_FRAME
	INT32 api_mcas_start_transponder(UINT32 mon_id)
	{
		MEMSET(stCA_EMM, 0, sizeof(stCA_EMM));
		sim_register_scb(mon_id, mcas_cat_section_callback, NULL);
		return SUCCESS;
	}
#else
	INT32 api_mcas_start_transponder( )
	{
		//here can clear the emm info table
		MEMSET(stCA_EMM, 0, sizeof(stCA_EMM));
		si_monitor_register_cat_cb((section_parse_cb_t)mcas_cat_section_callback);
		return SUCCESS;
	}
#endif
#else
	INT32 api_mcas_start_transponder()
	{
		//here can clear the emm info table
		MEMSET(stCA_EMM, 0, sizeof(stCA_EMM));

		//if not request cat yet
		if(cat_filter.pid == 0)
		{
			MCAS_DEBUG_PRINTF("api_mcas_start_transponder: start CAT\n");
			mcas_send_msg(MCAS_START_CAT, 0);
		}
		return SUCCESS;
	}
#endif

#ifdef GET_CAT_BY_SIM
  #ifdef NEW_DEMO_FRAME
	INT32 api_mcas_stop_transponder( UINT32 mon_id )
	{
		if(emm_filter.pid != 0)
		{
			mcas_stop_filter(&emm_filter);
			MCAS_DEBUG_PRINTF("api_mcas_stop_transponder: stop EMM\n");
			mcas_structure.state &= ~MCAS_STATE_EMM;
		}

		sim_unregister_scb(mon_id, mcas_cat_section_callback);
		return SUCCESS;
	}
  #else
	INT32 api_mcas_stop_transponder( )
	{
		if(emm_filter.pid != 0)
		{
			mcas_stop_filter(&emm_filter);
			MCAS_DEBUG_PRINTF("api_mcas_stop_transponder: stop EMM\n");
			mcas_structure.state &= ~MCAS_STATE_EMM;
		}
		si_monitor_unregister_cat_cb((section_parse_cb_t)mcas_cat_section_callback);
		return SUCCESS;
	}

  #endif
#else
	INT32 api_mcas_stop_transponder( )
	{
		if(emm_filter.pid != 0)
		{
			mcas_stop_filter(&emm_filter);
			MCAS_DEBUG_PRINTF("api_mcas_stop_transponder: stop EMM\n");
			mcas_structure.state &= ~MCAS_STATE_EMM;
		}

		if(cat_filter.pid != 0)
		{
			mcas_stop_filter(&cat_filter);;
			MCAS_DEBUG_PRINTF("api_mcas_stop_transponder: stop CAT\n");
			mcas_structure.state &= ~MCAS_STATE_CAT;
		}
		return SUCCESS;
	}
#endif



//callback function for card driver to send card in and out msg
static void mcas_card0_notify(UINT32 param)
{
	if(param == 0)
	{
		mcas_send_msg(MCAS_CARD_OUT, 0);
	}
	else if(param == 1)
	{
		mcas_send_msg(MCAS_CARD_IN, 0);
	}
}

static void mcas_card1_notify(UINT32 param)
{
	if(param == 0)
	{
		mcas_send_msg(MCAS_CARD_OUT, 1);
	}
	else if(param == 1)
	{
		mcas_send_msg(MCAS_CARD_IN, 1);
	}
}

/*********************************************************
pmt parsing, ecm, cat, emm request
**********************************************************/

static void mcas_pmt_section_callback(UINT8 *section, INT32 length, UINT16 param)
{
	UINT16 prog_info_len,section_len,es_info_len;
	UINT16 left_len;
	UINT16 prg_number;
	UINT8 *discriptor_pointer = NULL;
	UINT8 *discriptor_pointer2 = NULL;
	UINT8 loop_length;
	UINT16 ca_discriptor_num;
	UINT16 ecm_pid = 0;
	UINT16 match_card_num;
	UINT8 card_inited;
	UINT32 crc_value;
	UINT16 system_id;
		
	ca_discriptor_num = 0;
	match_card_num = 0;
	
	prg_number = (section[3]<<8) | section[4];	
	section_len = ((section[1] & 0x03) << 8)|section[2];

	crc_value = (section[section_len-1] |(section[section_len]<<8)|(section[section_len+1]<<16)|(section[section_len+2]<<24));
	//pmt data not change
	if(crc_value == pmt_crc_value)
	{
		MCAS_DEBUG_PRINTF("PMT section content not change, return!");
		return;
	}

	used_ecm_count = 0;
	
	prog_info_len = ((section[10] & 0x03) << 8)|section[11];
	left_len = section_len -9 -prog_info_len -4;

	MCAS_DEBUG_PRINTF("PMT section:");
	MCAS_DEBUG_DUMP(section, section_len+3);
	
	discriptor_pointer = &section[12];
	discriptor_pointer2 = discriptor_pointer + prog_info_len;

	//first loop, prog_info_length
	MCAS_DEBUG_PRINTF("pmt_section_callback():prog_info_len = %d\n", prog_info_len);
	MCAS_DEBUG_PRINTF("		parsing pmt loop1:\n");
	while (prog_info_len > 0)
	{
		/*the CA descriptor tag*/
		if (*discriptor_pointer == 0x09)
		{
			ca_discriptor_num++;
			ecm_pid = ((discriptor_pointer[4]&0x1F)<<8)|discriptor_pointer[5];
			system_id = ((discriptor_pointer[2]<<8)|discriptor_pointer[3]);
			//check card exist and match or not
			if(mcas_card_exist() == TRUE)
			{
				if(mcas_card_match(discriptor_pointer, &card_inited) != NULL)
				{
					pmt_crc_value = crc_value;
					MCAS_DEBUG_PRINTF("$$$ecm matched card, ecm_pid=0x%x, ca_system_id=0x%x \n",ecm_pid,system_id);
					stCA_ECM[match_card_num].ca_system_id = system_id;
					stCA_ECM[match_card_num].ecm_pid       = ecm_pid;
					match_card_num++;
					used_ecm_count++;
					
				}
				//if no matched card,clear crc value to make pmt parsing continously
				else
				{
					pmt_crc_value = 0;
				}
			}
			//no card, clear crc value to make pmt parsing continously
			else
			{
				pmt_crc_value = 0;
			}
			
			MCAS_DEBUG_PRINTF("		find ca descriptor, system id 0x%x, ecm pid %d\n",((discriptor_pointer[2]<<8)|discriptor_pointer[3]),ecm_pid);
		}
		prog_info_len -= 2+discriptor_pointer[1];
		discriptor_pointer += 2+discriptor_pointer[1];
	}
	discriptor_pointer = discriptor_pointer2;

	//second loop, N1, es_info_length
	MCAS_DEBUG_PRINTF("		componet info len = %d\n", left_len);
	MCAS_DEBUG_PRINTF("		parsing pmt loop2:\n");
	while(left_len > 0)
	{
		es_info_len = ((discriptor_pointer[3]&0x03)<<8)  | discriptor_pointer[4];
		loop_length = es_info_len;
		discriptor_pointer += 5;
		
		while(loop_length > 0)
		{
			/*the CA descriptor tag*/
			if (*discriptor_pointer == 0x09)
			{
				ca_discriptor_num++;
				
				ecm_pid = ((discriptor_pointer[4]&0x1F)<<8)|discriptor_pointer[5];
				system_id = ((discriptor_pointer[2]<<8)|discriptor_pointer[3]);
				//check card exist and match or not
				if(mcas_card_exist() == TRUE)
				{
					if(mcas_card_match(discriptor_pointer, &card_inited) != NULL)
					{
						pmt_crc_value = crc_value;
						MCAS_DEBUG_PRINTF("$$$ecm matched card, ecm_pid=0x%x, ca_system_id=0x%x \n",ecm_pid,system_id);
						stCA_ECM[match_card_num].ca_system_id = system_id;
						stCA_ECM[match_card_num].ecm_pid       = ecm_pid;
						match_card_num++;
						used_ecm_count++;
					}
					//if no matched card,clear crc value to make pmt parsing continously
					else
					{
						pmt_crc_value = 0;
					}
				}
				//no card, clear crc value to make pmt parsing continously
				else
				{
					pmt_crc_value = 0;
				}
				
				MCAS_DEBUG_PRINTF("		find ca descriptor, system id 0x%x, ecm pid %d\n",((discriptor_pointer[2]<<8)|discriptor_pointer[3]),ecm_pid);
			}
			loop_length -= 2+discriptor_pointer[1];
			discriptor_pointer += 2+discriptor_pointer[1];
		}
		left_len -= 5+es_info_len;
	}
	
	
	if(match_card_num > 0)
	{
		
		uiCurrentTryingCount = 0;
		mcas_send_msg(MCAS_START_ECM, 0);
	}
	
	return;
}

#ifdef GET_CAT_BY_SIM
static INT32 mcas_cat_section_callback(UINT8 *buffer, INT32  len , UINT16 param)
{
	UINT16 index;
	UINT16 cat_length;
	UINT16 ca_system_id = 0;
	UINT16 provide_id = 0;
	UINT16 emm_pid = 0;
	UINT8 card_inited;
	UINT8 match_card_num = 0;
	
	used_emm_count = 0;
	
	cat_length = ((buffer[1]&0x0F)<<8) | buffer[2];
	
	MCAS_DEBUG_PRINTF("CAT section:");
	MCAS_DEBUG_DUMP(buffer, len+3);
	
	index = 8;
	cat_length -= 9;	/*only length of ca_discriptor*/
	MCAS_DEBUG_PRINTF("parse_cat():section len=%d,section num %d, last section num %d\n", cat_length,buffer[6],buffer[7]);
	while(cat_length > 0)
	{
		if (buffer[index] == 0x09)
		{
			
			ca_system_id = (buffer[index+2] << 8) | buffer[index+3];
			emm_pid = ((buffer[index+4]&0x1F)<<8) | buffer[index+5];

			//check card exist and match or not
			if(mcas_card_exist() == TRUE)
			{
				if(mcas_card_match(&buffer[index], &card_inited) != NULL)
				{
					MCAS_DEBUG_PRINTF("$$$emm matched card, emm_pid=0x%x, ca_system_id=0x%x \n",emm_pid,ca_system_id);
					stCA_EMM[match_card_num].ca_system_id = ca_system_id;
					stCA_EMM[match_card_num].emm_pid       = emm_pid;
					match_card_num++;
					used_emm_count++;
				}
			}
			
			MCAS_DEBUG_PRINTF("		find ca descriptor, system id 0x%04x, emm_pid 0x%04x\n", ca_system_id, emm_pid);
			//here can copy the emm data

			
		}
		cat_length -= 2 + buffer[index+1];
		index += 2 + buffer[index+1];
	}
		
	if(match_card_num > 0)
	{
		mcas_send_msg(MCAS_START_EMM, 0);
	}
	
	return RET_SUCCESS;
}
#endif

static INT32 mcas_parse_cat(UINT8 *buffer, UINT16 len)
{
	UINT16 index;
	UINT16 cat_length;
	UINT16 ca_system_id = 0;
	UINT16 provide_id = 0;
	UINT16 emm_pid = 0;
	UINT8 card_inited;
	UINT8 match_card_num = 0;
	
	used_emm_count = 0;
	
	cat_length = ((buffer[1]&0x0F)<<8) | buffer[2];
	
	MCAS_DEBUG_PRINTF("CAT section:");
	MCAS_DEBUG_DUMP(buffer, len+3);
	
	index = 8;
	cat_length -= 9;	/*only length of ca_discriptor*/
	MCAS_DEBUG_PRINTF("parse_cat():section len=%d,section num %d, last section num %d\n", cat_length,buffer[6],buffer[7]);
	while(cat_length > 0)
	{
		if (buffer[index] == 0x09)
		{
			
			ca_system_id = (buffer[index+2] << 8) | buffer[index+3];
			emm_pid = ((buffer[index+4]&0x1F)<<8) | buffer[index+5];

			//check card exist and match or not
			if(mcas_card_exist() == TRUE)
			{
				if(mcas_card_match(&buffer[index], &card_inited) != NULL)
				{
					MCAS_DEBUG_PRINTF("$$$emm matched card, emm_pid=0x%x, ca_system_id=0x%x \n",emm_pid,ca_system_id);
					stCA_EMM[match_card_num].ca_system_id = ca_system_id;
					stCA_EMM[match_card_num].emm_pid       = emm_pid;
					match_card_num++;
					used_emm_count++;
				}
			}
			
			MCAS_DEBUG_PRINTF("		find ca descriptor, system id 0x%04x, emm_pid 0x%04x\n", ca_system_id, emm_pid);
			//here can copy the emm data

			
		}
		cat_length -= 2 + buffer[index+1];
		index += 2 + buffer[index+1];
	}
		
	if(match_card_num > 0)
	{
		mcas_send_msg(MCAS_START_EMM, 0);
	}
	
	return RET_SUCCESS;
}



static UINT8 uiAvailableIndex;
static UINT8 ucTempECMbuff[255];
static UINT16 uiTempECMleng;

#ifdef LIB_TSI3_FULL
static void on_receive_ecm(UINT16 pid, struct si_filter_t *filter, UINT8 reason, UINT8 *data, INT32 length)
{
	UINT16 len = 0;
	UINT8  i = 0;
	UINT8  matched_index = 0;
	struct si_filter_param fparam;
	MEMSET(&fparam, 0, sizeof(struct si_filter_param));
	sie_copy_config(filter, &fparam);

	if(data != NULL)
	{
		len = ((data[1]&0xF)<<8) |data[2];
		MCAS_DEBUG_PRINTF("on_receive_ecm(): ecm table id 0x%x,data len %d\n",data[0],len);
		//change table id if need
		fparam.mask_value.mask[0] = 0xFF;
		if(data[0] == 0x80)
			fparam.mask_value.value[0][0] = 0x81;
		
		else if(data[0] == 0x81)
			fparam.mask_value.value[0][0] = 0x80;
		
		MEMCPY(&ecm_filter.filter_restrict, &fparam.mask_value, sizeof(struct restrict));
		//here can copy the ecm data
		MCAS_DEBUG_PRINTF("ECM section:");
		MCAS_DEBUG_DUMP(data, len+3);
		MEMCPY(ucTempECMbuff,data,len+3);
		uiTempECMleng = len+3;

		for(i=0;i<16;i++)
		{
			if(pid == stCA_ECM[i].ecm_pid)
			{
				matched_index = i;
				break;
			}
		}
		
		if(i == 16)
		{
			MCAS_DEBUG_PRINTF("Reached Max_ECM \n");
			uiAvailableIndex = 0xFF;
		}
		else
		{
			//parsing the available CA system.
			uiAvailableIndex = matched_index;
			mcas_send_msg(MCAS_GOT_ECM, 0);
		}
	}
}

INT32 mcas_request_ecm(UINT16 ecm_pid, UINT8 ecm_table_id, UINT16 ca_system_id)
{
	INT32 slot;
	INT32 ret = RET_SUCCESS;
	UINT8 i;
	struct si_filter_t *sfilter = NULL;
	struct si_filter_param fparam;
	//ECM table id:0x80 or 0x81
	MEMSET(&fparam, 0, sizeof(struct si_filter_param));
	fparam.timeout = OSAL_WAIT_FOREVER_TIME;
	fparam.mask_value.mask_len = 1;
	fparam.mask_value.mask[0] = 0xFE;
//	fparam.mask_value.mask[1] = 0x80;//for section_syntax_indicator bit
	
	fparam.mask_value.value_num = 1;
	fparam.mask_value.value[0][0] = ecm_table_id;
//	fparam.mask_value.value[0][1] = 0x80;

	fparam.section_event = NULL;
	fparam.section_parser = (si_handler_t)on_receive_ecm;
  
	ecm_filter.pid = ecm_pid;
	ecm_filter.ca_system_id = ca_system_id;
	MEMCPY(&ecm_filter.filter_restrict, &fparam.mask_value, sizeof(struct restrict));

	for(i=0; i<3; i++)
	{
		ret = RET_SUCCESS;
		
		sfilter = sie_alloc_filter(ecm_filter.pid, ecm_buffer, MAX_CMT_LENGTH, MAX_CMT_LENGTH);
		if(sfilter == NULL)
		{
			//SIEM_PRINTF("%s(): alloc filter failed!\n", __FUNCTION__);
			return ERR_FAILUE;
		}
		sie_config_filter(sfilter, &fparam);
		ret = sie_enable_filter(sfilter);
		
		
		if(ret==RET_SUCCESS)
			break;
		else
			osal_task_sleep(10);
	}
	return ret;
}
static void on_receive_cat(UINT16 pid, struct si_filter_t *filter, UINT8 reason, UINT8 *data, INT32 length)
{
	UINT16 len = 0;
	INT32 siae_id;
	struct si_filter_param fparam;
	MEMSET(&fparam, 0, sizeof(struct si_filter_param));
	sie_copy_config(filter, &fparam);

	if(data != NULL)
	{
		len = ((data[1]&0xF)<<8) |data[2];

		mcas_parse_cat(data, len);

		
		sie_abort(pid, &fparam.mask_value);
				
		mcas_send_msg(MCAS_GOT_CAT, 0);
	}

}

INT32 mcas_request_cat()
{
	INT32 ret = RET_SUCCESS;
	struct si_filter_param fparam;
	struct si_filter_t *sfilter = NULL;
	
	MEMSET(&fparam, 0, sizeof(struct si_filter_param));
	fparam.timeout = OSAL_WAIT_FOREVER_TIME;
	fparam.attr[0] = SI_ATTR_HAVE_CRC32;
	fparam.mask_value.mask_len = 6;
	fparam.mask_value.mask[0] = 0xFF;
	fparam.mask_value.mask[1] = 0xC0;
	fparam.mask_value.mask[2] = 0x01;
	
	fparam.mask_value.value_num = 1;
	fparam.mask_value.value[0][0] = 0x01;
	fparam.mask_value.value[0][1] = 0x80;
	fparam.mask_value.value[0][2] = 0x01;

	fparam.section_event = NULL;
	fparam.section_parser = (si_handler_t)on_receive_cat;


	cat_filter.pid = 0x01;
	MEMCPY(&cat_filter.filter_restrict, &fparam.mask_value, sizeof(struct restrict));	

	sfilter = sie_alloc_filter(cat_filter.pid, cat_buffer, SECTION_BUFFER_SIZE, SECTION_BUFFER_SIZE);
	if(sfilter == NULL)
	{
		//SIEM_PRINTF("%s(): alloc filter failed!\n", __FUNCTION__);
		return ERR_FAILUE;
	}
	sie_config_filter(sfilter, &fparam);
	ret = sie_enable_filter(sfilter);
	return ret;
}

static void on_receive_emm(UINT16 pid, struct si_filter_t *filter, UINT8 reason, UINT8 *data, INT32 length)
{
	UINT16 len = 0;
	struct si_filter_param fparam;
	MEMSET(&fparam, 0, sizeof(struct si_filter_param));
	sie_copy_config(filter, &fparam);

	if(data != NULL)
	{
		len = ((data[1]&0xF)<<8) |data[2];
		MCAS_DEBUG_PRINTF("on_receive_emm(): emm table id 0x%x,data len %d\n",data[0],len);
		//change table id if need
		
		//here can copy the emm data

		MCAS_DEBUG_PRINTF("EMM section:");
		MCAS_DEBUG_DUMP(data, len+3);
	
		//stop emm filter
		
		//not stop emm filter, maybe need several emm sections
		
		mcas_send_msg(MCAS_GOT_EMM, 0);
	}
}

INT32 mcas_request_emm(UINT16 emm_pid, UINT8 emm_table_id, UINT16 ca_system_id)
{

	INT32 ret = RET_SUCCESS;
	struct si_filter_t *sfilter = NULL;
	struct si_filter_param fparam;
	
	MEMSET(&fparam, 0, sizeof(struct si_filter_param));
	fparam.timeout = OSAL_WAIT_FOREVER_TIME;
	fparam.mask_value.mask_len = 2;
	fparam.mask_value.mask[0] = 0xFF;
	fparam.mask_value.mask[1] = 0x80;
	
	fparam.mask_value.value_num = 1;
	fparam.mask_value.value[0][0] = emm_table_id;
	fparam.mask_value.value[0][1] = 0x00;

	fparam.section_event = NULL;
	fparam.section_parser = (si_handler_t)on_receive_emm;

	emm_filter.pid = emm_pid;
	emm_filter.ca_system_id = ca_system_id;
	MEMCPY(&emm_filter.filter_restrict, &fparam.mask_value, sizeof(struct restrict));
	 
	sfilter = sie_alloc_filter(emm_filter.pid, emm_buffer, MAX_CMT_LENGTH, MAX_CMT_LENGTH);
	if(sfilter == NULL)
	{
		//SIEM_PRINTF("%s(): alloc filter failed!\n", __FUNCTION__);
		return ERR_FAILUE;
	}
	sie_config_filter(sfilter, &fparam);
	ret = sie_enable_filter(sfilter);
	if(ret != SUCCESS)
	{
		ret = ERR_FAILUE;
	}
	
	return ret;
}
#else
static void on_receive_ecm(struct si_request *sr, UINT8 *data)
{
	UINT16 len = 0;
	UINT8  i = 0;
	UINT8  matched_index = 0;

	if(data != NULL)
	{
		len = ((data[1]&0xF)<<8) |data[2];
		MCAS_DEBUG_PRINTF("on_receive_ecm(): ecm table id 0x%x,data len %d\n",data[0],len);
		//change table id if need
		sr->sr_restrict.mask[0] = 0xFF;
		if(data[0] == 0x80)
			sr->sr_restrict.value[0][0] = 0x81;
		
		else if(data[0] == 0x81)
			sr->sr_restrict.value[0][0] = 0x80;
		
		MEMCPY(&ecm_filter.filter_restrict, &sr->sr_restrict, sizeof(struct restrict));
		//here can copy the ecm data
		MCAS_DEBUG_PRINTF("ECM section:");
		MCAS_DEBUG_DUMP(data, len+3);
		MEMCPY(ucTempECMbuff,data,len+3);
		uiTempECMleng = len+3;

		for(i=0;i<16;i++)
		{
			if(sr->sr_request.pid == stCA_ECM[i].ecm_pid)
			{
				matched_index = i;
				break;
			}
		}
		
		if(i == 16)
		{
			MCAS_DEBUG_PRINTF("Reached Max_ECM \n");
			uiAvailableIndex = 0xFF;
		}
		else
		{
			//parsing the available CA system.
			uiAvailableIndex = matched_index;
			mcas_send_msg(MCAS_GOT_ECM, 0);
		}
	}
}

INT32 mcas_request_ecm(UINT16 ecm_pid, UINT8 ecm_table_id, UINT16 ca_system_id)
{
	struct si_request sr;
	INT32 slot, siae_id;
	INT32 ret = RET_SUCCESS;
	UINT8 i;

	MEMSET(&sr, 0, sizeof(sr));
	//set request param
	sr.sr_confined = 1;
	
	sr.sr_handler = (sr_handler_t)on_receive_ecm;

	sr.sr_request.buff = ecm_buffer;
	sr.sr_request.buff_len = MAX_CMT_LENGTH;

	sr.sr_request.pid = ecm_pid;
	sr.sr_timeout = SR_TIMEOUT_UNLIMIT;
	sr.sr_restrict.mask_len = 2;
	sr.sr_restrict.mask[0] = 0xFE;		/* Table ID */
	sr.sr_restrict.mask[1] = 0x80;		/* Section syntax indicator */
			
	sr.sr_restrict.value_num = 1;
	sr.sr_restrict.value[0][0] = ecm_table_id;	/* Table ID */
	sr.sr_restrict.value[0][1] = 0x00;
	     
	ecm_filter.pid = sr.sr_request.pid;
	ecm_filter.ca_system_id = ca_system_id;
	MEMCPY(&ecm_filter.filter_restrict, &sr.sr_restrict, sizeof(struct restrict));

	for(i=0; i<3; i++)
	{
		ret = RET_SUCCESS;
		siae_id = siae_acquire_id();
		if (siae_id < 0) 
		{
			MCAS_DEBUG_PRINTF("api_cas_request_ecm():siae id < 0!\n");
			ret = ERR_FAILUE;
		}
		slot = siae_request(siae_id, &sr);
		if ((slot>SIAE_SLOT_NUMBER)||(slot<0)) 
		{
			MCAS_DEBUG_PRINTF("		slot request failure!\n");
			ret = ERR_FAILUE;
		}
		if(ret==RET_SUCCESS)
			break;
		else
			osal_task_sleep(10);
	}
	return ret;
}

static void on_receive_cat(struct si_request *sr, UINT8 *data)
{
	UINT16 len = 0;
	INT32 siae_id;

	if(data != NULL)
	{
		len = ((data[1]&0xF)<<8) |data[2];

		mcas_parse_cat(data, len);

		siae_id = siae_acquire_id();
		if (siae_id < 0) 
		{
			MCAS_DEBUG_PRINTF("	on_receive_cat():siae id < 0!\n");
			return;
		}
		siae_abort(siae_id, sr->sr_request.pid, &(sr->sr_restrict));
				
		mcas_send_msg(MCAS_GOT_CAT, 0);
	}

}

INT32 mcas_request_cat()
{
	struct si_request sr;
	INT32 slot, siae_id;
	INT32 ret = RET_SUCCESS;

	MEMSET(&sr, 0, sizeof(sr));
	//set request param
	sr.sr_confined = 1;
	sr.sr_request.crc_flag = 1;
	
	sr.sr_handler = (sr_handler_t)on_receive_cat;

	sr.sr_request.buff = cat_buffer;
	sr.sr_request.buff_len = SECTION_BUFFER_SIZE;

	sr.sr_request.pid = 0x01;
	sr.sr_timeout = SR_TIMEOUT_UNLIMIT;
	sr.sr_restrict.mask_len = 6;
	sr.sr_restrict.mask[0] = 0xFF;	/* Table ID */
	sr.sr_restrict.mask[1] = 0xC0;	/* Section syntax indicator */
	sr.sr_restrict.mask[5] = 0x01;     /* Current next indicator */
		
	sr.sr_restrict.value_num = 1;
	sr.sr_restrict.value[0][0] = 0x01;		/* Table ID */
	sr.sr_restrict.value[0][1] = 0x80;		/* Section syntax indicator */
	sr.sr_restrict.value[0][5] = 0x01;		/* Current next indicator */

	cat_filter.pid = sr.sr_request.pid;
	MEMCPY(&cat_filter.filter_restrict, &sr.sr_restrict, sizeof(struct restrict));	
	
	siae_id = siae_acquire_id();
	if (siae_id < 0) 
	{
		MCAS_DEBUG_PRINTF("api_cas_request_cat():siae id < 0!\n");
		return ERR_FAILUE;
	}
	slot = siae_request(siae_id, &sr);
	if ((slot>SIAE_SLOT_NUMBER)||(slot<0)) 
	{
		MCAS_DEBUG_PRINTF("		slot request failure!\n");
		ret = ERR_FAILUE;
	}
	return ret;
}

static void on_receive_emm(struct si_request *sr, UINT8 *data)
{
	UINT16 len = 0;
	INT32 siae_id;

	if(data != NULL)
	{
		len = ((data[1]&0xF)<<8) |data[2];
		MCAS_DEBUG_PRINTF("on_receive_emm(): emm table id 0x%x,data len %d\n",data[0],len);
		//change table id if need
		
		//here can copy the emm data

		MCAS_DEBUG_PRINTF("EMM section:");
		MCAS_DEBUG_DUMP(data, len+3);
	
		//stop emm filter
		siae_id = siae_acquire_id();
		if (siae_id < 0) 
		{
			MCAS_DEBUG_PRINTF("		siae id < 0!\n");
			return;
		}
		//not stop emm filter, maybe need several emm sections
		//siae_abort(siae_id, sr->sr_request.pid, &(sr->sr_restrict));
		
		mcas_send_msg(MCAS_GOT_EMM, 0);
	}
}

INT32 mcas_request_emm(UINT16 emm_pid, UINT8 emm_table_id, UINT16 ca_system_id)
{
	struct si_request sr;
	INT32 slot, siae_id;
	INT32 ret = RET_SUCCESS;

	MEMSET(&sr, 0, sizeof(sr));
	//set request param
	sr.sr_confined = 1;
	
	sr.sr_handler = (sr_handler_t)on_receive_emm;

	sr.sr_request.buff = emm_buffer;
	sr.sr_request.buff_len = MAX_CMT_LENGTH;

	sr.sr_request.pid = emm_pid;
	sr.sr_timeout = SR_TIMEOUT_UNLIMIT;
	sr.sr_restrict.mask_len = 2;
	sr.sr_restrict.mask[0] = 0xFF;		/* Table ID */
	sr.sr_restrict.mask[1] = 0x80;		/* Section syntax indicator */
		
	sr.sr_restrict.value_num = 1;
	sr.sr_restrict.value[0][0] = emm_table_id;	/* Table ID */
	sr.sr_restrict.value[0][1] = 0x00;	/* Section syntax indicator */

	emm_filter.pid = sr.sr_request.pid;
	emm_filter.ca_system_id = ca_system_id;
	MEMCPY(&emm_filter.filter_restrict, &sr.sr_restrict, sizeof(struct restrict));
	 
	siae_id = siae_acquire_id();
	if (siae_id < 0) 
	{
		MCAS_DEBUG_PRINTF("api_cas_request_emm():siae id < 0!\n");
		return ERR_FAILUE;
	}
	slot = siae_request(siae_id, &sr);
	if ((slot>SIAE_SLOT_NUMBER)||(slot<0)) 
	{
		MCAS_DEBUG_PRINTF("		slot request failure!\n");
		ret = ERR_FAILUE;
	}
	return ret;
}
#endif

/*********************************************************

**********************************************************/


//declare
static void mcas_main_thread(UINT32 param1, UINT32 param2);

INT32 api_mcas_register(mcas_disp_func_t mcas_disp_func)
{
	OSAL_T_CTSK t_ctsk;
	OSAL_T_CMBF t_cmbf;
	struct dmx_device *dmx_dev;

	dmx_dev = (struct dmx_device *)dev_get_by_type(NULL, HLD_DEV_TYPE_DMX);
	dmx_io_control(dmx_dev, DMX_BYPASS_CSA, 0);

	MEMSET(&mcas_structure, 0, sizeof(mcas_t));
	mcas_structure.disp_callback = mcas_disp_func;
	
	MEMSET(&ecm_filter, 0, sizeof(cas_filter_t));

#ifndef GET_CAT_BY_SIM
	MEMSET(&cat_filter, 0, sizeof(cas_filter_t));
#endif

	MEMSET(&emm_filter, 0, sizeof(cas_filter_t));
	
	/* create massage buffer */
	t_cmbf.bufsz = 32*sizeof(mcas_msg_t);
	t_cmbf.maxmsz = 32;
	mcas_structure.msgque_id = osal_msgqueue_create(&t_cmbf);
	if (OSAL_INVALID_ID == mcas_structure.msgque_id)
	{
		MCAS_DEBUG_PRINTF("api_mcas_register: create msg queue error!\n");
		ASSERT(0);
	}

	/* create main thread */
	t_ctsk.task = (OSAL_T_TASK_FUNC_PTR)mcas_main_thread;
	t_ctsk.itskpri = OSAL_PRI_NORMAL;
	t_ctsk.stksz = 0x1000;
	t_ctsk.quantum = 10;
	t_ctsk.name[0] = 'M';
	t_ctsk.name[1] = 'C';
	t_ctsk.name[2] = 'A';
	mcas_structure.thread_id = osal_task_create(&t_ctsk);
	if (OSAL_INVALID_ID == mcas_structure.thread_id)
	{
		MCAS_DEBUG_PRINTF("api_mcas_register: create main thread error!\n");
		ASSERT(0);
	}
#ifndef NEW_DEMO_FRAME
	si_monitor_register_pmt_cb((section_parse_cb_t)mcas_pmt_section_callback);
#endif

	
	mcas_structure.state = MCAS_STATE_IDLE;
	return RET_SUCCESS;
}


INT32 api_mcas_unregister()
{
	struct dmx_device *dmx_dev;

	dmx_dev = (struct dmx_device *)dev_get_by_type(NULL, HLD_DEV_TYPE_DMX);
	dmx_io_control(dmx_dev, DMX_BYPASS_CSA, 1);

	si_monitor_unregister_pmt_cb((section_parse_cb_t)mcas_pmt_section_callback);

#ifdef GET_CAT_BY_SIM
	si_monitor_unregister_cat_cb((section_parse_cb_t)mcas_cat_section_callback);
#endif

//	si_monitor_register_pmt_cb((section_parse_cb_t)NULL);
	/* delete cas_emu thread */
	osal_task_delete(mcas_structure.thread_id);
	/* delete cas_emu massage buffer */
	osal_msgqueue_delete(mcas_structure.msgque_id);
	mcas_structure.disp_callback = NULL;
	mcas_structure.state= MCAS_STATE_UNREGISTER;

	return RET_SUCCESS;
}

void api_mcas_write_cw(struct dmx_device *dmx_dev, UINT8 *dcw, UINT8 resend)
{
	UINT8 i;
	static UINT8 last_even_cw[8], last_odd_cw[8];
	
	for(i=0; i<16; i+=4) dcw[i+3] = dcw[i] + dcw[i+1] + dcw[i+2];

	if(resend || MEMCMP(&dcw[0], last_even_cw, 8))
	{
		MEMCPY(last_even_cw, &dcw[0], 8);
		dmx_cfg_cw(dmx_dev, DES_VIDEO, 2, (UINT32 *)last_even_cw);
		dmx_cfg_cw(dmx_dev, DES_AUDIO, 2, (UINT32 *)last_even_cw);
	}

	if(resend || MEMCMP(&dcw[8], last_odd_cw, 8))
	{
		MEMCPY(last_odd_cw, &dcw[8], 8);
		dmx_cfg_cw(dmx_dev, DES_VIDEO, 3, (UINT32 *)last_odd_cw);
		dmx_cfg_cw(dmx_dev, DES_AUDIO, 3, (UINT32 *)last_odd_cw);
	}
}



static void mcas_main_thread(UINT32 param1, UINT32 param2)
{
	struct smc_device *smc_dev[MCAS_CARD_MAX_NUM];
	struct dmx_device *dmx_dev;
	mcas_msg_t mcas_msg;
	UINT32 msg_len;
	UINT8  i;
	mcas_card_t card_info;
	UINT16 ca_system_id;
		
	dmx_dev = (struct dmx_device *)dev_get_by_type(NULL, HLD_DEV_TYPE_DMX);

	//open smc card
	smc_dev[0] = (struct smc_device *)dev_get_by_id(HLD_DEV_TYPE_SMC, 0);
	if(smc_dev[0] != NULL)
	{
		if(RET_SUCCESS != smc_open(smc_dev[0], mcas_card0_notify))
		{
			MCAS_DEBUG_PRINTF("mcas_main_thread: 0 smc_open failed!!\n");
			ASSERT(0);
		}
	}
	smc_dev[1] = (struct smc_device *)dev_get_by_id(HLD_DEV_TYPE_SMC, 1);
	if(smc_dev[1] != NULL)
	{
		if(RET_SUCCESS != smc_open(smc_dev[1], mcas_card1_notify))
		{
			MCAS_DEBUG_PRINTF("mcas_main_thread: 1 smc_open failed!!\n");
			ASSERT(0);
		}
	}

	while(1)
	{
		mcas_msg.type = MCAS_NULL;
		if (osal_msgqueue_receive(&mcas_msg, &msg_len, mcas_structure.msgque_id, 100) != RET_SUCCESS)
		{
			osal_task_sleep(10);
			continue;
		}
		switch (mcas_msg.type)
		{
			case MCAS_START_ECM:
				MCAS_DEBUG_PRINTF("Got message MCAS_START_ECM\n");
				//close the old filter
				if(ecm_filter.pid != 0)
					mcas_stop_filter(&ecm_filter);
				
				mcas_request_ecm(stCA_ECM[uiCurrentTryingCount].ecm_pid, 0x80, stCA_ECM[uiCurrentTryingCount].ca_system_id);
				
				mcas_structure.state |= MCAS_STATE_ECM;
				break;
			case MCAS_GOT_ECM:
				MCAS_DEBUG_PRINTF("Got message MCAS_GOT_ECM\n");
				//here can decrypt ecm

				//mcas_card_decoder(struct smc_device * smc_dev, UINT8 * ecm_data, UINT16 data_len, UINT8 * cw);
				
				break;
			case MCAS_STOP:
				
				mcas_structure.state = MCAS_STATE_IDLE;
				break;

#ifndef GET_CAT_BY_SIM
			case MCAS_START_CAT:
				MCAS_DEBUG_PRINTF("Got message MCAS_START_CAT\n");
				
				mcas_stop_filter(&cat_filter);
				mcas_request_cat();
				mcas_structure.state |= MCAS_STATE_CAT;
				break;

			case MCAS_GOT_CAT:
				MCAS_DEBUG_PRINTF("Got message MCAS_GOT_CAT\n");
#endif
				break;
			case MCAS_START_EMM:
				MCAS_DEBUG_PRINTF("Got message MCAS_START_EMM\n");
				mcas_stop_filter(&emm_filter);				
				//mcas_request_emm(stCA_EMM[i].emm_pid, 0x00,stCA_EMM[i].ca_system_id);

				mcas_structure.state |= MCAS_STATE_EMM;
				break;
			case MCAS_GOT_EMM:
				MCAS_DEBUG_PRINTF("Got message MCAS_GOT_EMM\n");
				//here can decrypt emm

				//mcas_card_update(struct smc_device * smc_dev, UINT8 * emm_data, UINT16 data_len);
				
				break;
			case MCAS_CARD_IN:
				MCAS_DEBUG_PRINTF("Got message MCAS_CARD_IN\n");
				//UI display
				if(mcas_structure.disp_callback != NULL)
					mcas_structure.disp_callback(MCAS_DISP_CARD_IN, mcas_msg.param);
				
				ca_system_id = 0;
				if(SUCCESS == mcas_card_in((UINT8)mcas_msg.param, smc_dev[mcas_msg.param], &ca_system_id))
				{
					//UI display
					if(mcas_structure.disp_callback != NULL)
						mcas_structure.disp_callback(MCAS_DISP_CARD_INITED, mcas_msg.param|ca_system_id);
				}

				mcas_stop_filter(&ecm_filter);
				//here can clear ecm info table
				MEMSET(stCA_ECM, 0, sizeof(stCA_ECM));
				
				//clear the pmt crc value to enable the pmt parsing again
				pmt_crc_value = 0;
				
				break;
			case MCAS_CARD_OUT:
				MCAS_DEBUG_PRINTF("Got message MCAS_CARD_OUT\n");
				//UI display
				if(mcas_structure.disp_callback != NULL)
					mcas_structure.disp_callback(MCAS_DISP_CARD_OUT, mcas_msg.param);	
				
				mcas_card_out(smc_dev[mcas_msg.param]);
				//if emm,cat filter is open, close them
				mcas_stop_filter(&emm_filter);

#ifndef GET_CAT_BY_SIM
				mcas_stop_filter(&cat_filter);
#endif				
				break;
			case MCAS_CARD_UPDATE:
				
				break;
			default:
				MCAS_DEBUG_PRINTF("Got unknow type message\n");
				break;
		}
	}

	
}

